#pragma once

#include "log_functor.hpp"

namespace zuck
{
	// only used for sequence container
	template<typename _Iterator>
	class reverse_iterator {
	private:
		using _Self = reverse_iterator<_Iterator>;
	public:
		using value_type		= typename _Iterator::value_type;
		using pointer			= typename _Iterator::pointer;
		using reference			= typename _Iterator::reference;
		using difference_type	= typename _Iterator::difference_type;
		using iterator_category = typename _Iterator::iterator_category;
	private:
		pointer _m_start;
		pointer _m_iter;
		pointer _m_end;
	public:
		explicit reverse_iterator(pointer iter, pointer start, pointer end)
			: _m_iter(iter), _m_start(start), _m_end(end) {}

		reverse_iterator(const _Self& other)
			: _m_iter(other._m_iter), _m_start(other._m_start)
            , _m_end(other._m_end)
        {}

		reverse_iterator(_Self&& other)noexcept
			: _m_iter(other._m_iter), _m_start(other._m_start)
            , _m_end(other._m_end)
		{
			other._m_iter  = null;
			other._m_start = null;
			other._m_end   = null;
		}

        ~reverse_iterator()
        {
            _m_iter  = null;
            _m_start = null;
            _m_end   = null;
        }

	public:
		_Self& operator=(const _Self& other)
        {
			__copy_construct(other);
			return *this;
		}

		_Self& operator=(_Self&& other)noexcept
        {
			_m_iter  = other._m_iter;
			_m_start = other._m_start;
			_m_end   = other._m_end;
			other._m_iter  = null;
			other._m_start = null;
			other._m_end   = null;
			return *this;
		}

		[[nodiscard]] inline pointer operator->()noexcept  { return _m_iter; }

		[[nodiscard]] inline reference operator*()noexcept { return *_m_iter; }

        inline _Self& operator++()noexcept
        {
            if constexpr (debug_) {
                if (_m_iter < _m_start) {
                    debug_log::derror(zuck::SEG_WrongIter, 
                        "subscript out of range !");
                }
            }
			--_m_iter;
			return *this;
        }

        [[nodiscard]] inline _Self operator++(int)noexcept
        {
            auto _Tmp = *this;
            ++(*this);
            return _Tmp;
        }

        [[nodiscard]] _Self& operator+=(const difference_type step)noexcept
        {
            if constexpr (debug_) {
                if (_m_iter - step < _m_start) {
                    debug_log::derror(zuck::SEG_WrongIter,
                        "Segmentfault: subscript out of range !");
                }
            }
            _m_iter -= step;
            return *this;
        }

        [[nodiscard]] inline _Self operator+(const difference_type step)const noexcept
        {
            auto _Tmp = *this;
            return _Tmp += step;
        }

        inline _Self& operator--()noexcept
        {
            if constexpr (debug_) {
                if (_m_iter >= _m_end) {
                    debug_log::derror(zuck::SEG_WrongIter,
                        "Segmentfault: can not raferenced end iterator !");
                }
            }
            ++_m_iter;
            return *this;
        }

        [[nodiscard]] inline _Self operator--(int)noexcept
        {
            auto _Tmp = *this;
            --(*this);
            return _Tmp;
        }
 
        inline _Self& operator-=(const difference_type step)noexcept
        {
            if constexpr (debug_) {
                if (_m_iter + step >= _m_end) {
                    debug_log::derror(zuck::SEG_WrongIter,
                        "Segmentfault: subscript out of range !");
                }
            }
            _m_iter += step;
            return *this;
        }

        [[nodiscard]] inline _Self operator-(const difference_type step)const noexcept
        {
            auto _Tmp = *this;
            return _Tmp -= step;
        }

    public:
        [[nodiscard]] inline bool operator==(const _Self& other)const noexcept
        {
            return static_cast<bool>(_m_iter == other._m_iter);
        }

        [[nodiscard]] inline bool operator!=(const _Self& other)const noexcept
        {
            return static_cast<bool>(_m_iter != other._m_iter);
        }

        [[nodiscard]] inline bool operator<(const _Self& other)const noexcept
        {
            return static_cast<bool>(_m_iter < other._m_iter);
        }

        [[nodiscard]] inline bool operator<=(const _Self& other)const noexcept
        {
            return static_cast<bool>(_m_iter <= other._m_iter);
        }

        [[nodiscard]] inline bool operator>(const _Self& other)const noexcept
        {
            return static_cast<bool>(_m_iter > other._m_iter);
        }

        [[nodiscard]] inline bool operator>=(const _Self& other)const noexcept
        {
            return static_cast<bool>(_m_iter >= other._m_iter);
        }

	private:
		void inline __copy_construct(const _Self& other)
		{
			_m_iter  = other._m_iter;
			_m_start = other._m_start;
			_m_end   = other._m_end;
		}
	};
}

